<!DOCTYPE html><html lang="zh-Hans"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"><meta name="description" content="嵌入式复习"><meta name="keywords" content="嵌入式 复习"><meta name="author" content="晟松"><meta name="copyright" content="晟松"><title>嵌入式复习 | 晟松</title><link rel="shortcut icon" href="/logo.png"><link rel="stylesheet" href="/css/index.css?version=1.9.0"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/font-awesome@latest/css/font-awesome.min.css?version=1.9.0"><meta name="format-detection" content="telephone=no"><meta http-equiv="x-dns-prefetch-control" content="on"><link rel="dns-prefetch" href="https://cdn.jsdelivr.net"><link rel="dns-prefetch" href="https://hm.baidu.com"><script>var _hmt = _hmt || [];
(function() {
  var hm = document.createElement("script");
  hm.src = "https://hm.baidu.com/hm.js?c34d81d53341febe06a155941e2df16d";
  var s = document.getElementsByTagName("script")[0]; 
  s.parentNode.insertBefore(hm, s);
})();</script><meta http-equiv="Cache-Control" content="no-transform"><meta http-equiv="Cache-Control" content="no-siteapp"><script>var GLOBAL_CONFIG = { 
  root: '/',
  algolia: undefined,
  localSearch: {"path":"search.xml","languages":{"hits_empty":"找不到您查询的内容:${query}"}},
  copy: {
    success: '复制成功',
    error: '复制错误',
    noSupport: '浏览器不支持'
  },
  hexoVersion: '5.4.0'
} </script><meta name="generator" content="Hexo 5.4.0"></head><body><i class="fa fa-arrow-right" id="toggle-sidebar" aria-hidden="true"></i><div id="sidebar" data-display="true"><div class="toggle-sidebar-info text-center"><span data-toggle="切换文章详情">切换站点概览</span><hr></div><div class="sidebar-toc"><div class="sidebar-toc__title">目录</div><div class="sidebar-toc__progress"><span class="progress-notice">你已经读了</span><span class="progress-num">0</span><span class="progress-percentage">%</span><div class="sidebar-toc__progress-bar"></div></div><div class="sidebar-toc__content"><ol class="toc"><li class="toc-item toc-level-2"><a class="toc-link" href="#title%EF%BC%9A%E5%B5%8C%E5%85%A5%E5%BC%8F"><span class="toc-number">1.</span> <span class="toc-text">title：嵌入式</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E6%B1%87%E7%BC%9620-%E4%B8%AD%E6%96%AD20-%E5%AE%9A%E6%97%B6%E5%99%A820-30-uCOS30-40"><span class="toc-number">1.1.</span> <span class="toc-text">汇编20%+中断20%+定时器20-30%+uCOS30-40%</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#ucos"><span class="toc-number">1.1.1.</span> <span class="toc-text">ucos</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%A4%8D%E4%B9%A0"><span class="toc-number">1.2.</span> <span class="toc-text">复习</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#%E6%B1%87%E7%BC%96"><span class="toc-number">1.2.1.</span> <span class="toc-text">汇编</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E4%B8%AD%E6%96%AD"><span class="toc-number">1.2.2.</span> <span class="toc-text">中断</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E5%AE%9A%E6%97%B6%E5%99%A8"><span class="toc-number">1.2.3.</span> <span class="toc-text">定时器</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#ucos-1"><span class="toc-number">1.2.4.</span> <span class="toc-text">ucos</span></a></li></ol></li></ol></li></ol></div></div><div class="author-info hide"><div class="author-info__avatar text-center"><img src="/img/avatar.png"></div><div class="author-info__name text-center">晟松</div><div class="author-info__description text-center">晟松的博客</div><div class="follow-button"><a target="_blank" rel="noopener" href="https://gitee.com/cheng_song">Gitee</a></div><hr><div class="author-info-articles"><a class="author-info-articles__archives article-meta" href="/archives"><span class="pull-left">文章</span><span class="pull-right">52</span></a><a class="author-info-articles__tags article-meta" href="/tags"><span class="pull-left">标签</span><span class="pull-right">45</span></a></div></div></div><div id="content-outer"><div id="top-container" style="background-image: url(/img/blog-bg.jpg)"><div id="page-header"><span class="pull-left"> <a id="site-name" href="/">晟松</a></span><i class="fa fa-bars toggle-menu pull-right" aria-hidden="true"></i><span class="pull-right menus">   <a class="site-page" href="/">Home</a><a class="site-page" href="/archives">Archives</a><a class="site-page" href="/tags">Tags</a><a class="site-page" href="/categories">Categories</a></span><span class="pull-right"><a class="site-page social-icon search"><i class="fa fa-search"></i><span> 搜索</span></a></span></div><div id="post-info"><div id="post-title">嵌入式复习</div><div id="post-meta"><time class="post-meta__date"><i class="fa fa-calendar" aria-hidden="true"></i> 2021-06-05</time><div class="post-meta-wordcount"><span>字数总计: </span><span class="word-count">5.3k</span><span class="post-meta__separator">|</span><span>阅读时长: 19 分钟</span></div></div></div></div><div class="layout" id="content-inner"><article id="post"><div class="article-container" id="post-content"><h2 id="title：嵌入式"><a href="#title：嵌入式" class="headerlink" title="title：嵌入式"></a>title：嵌入式</h2><h3 id="汇编20-中断20-定时器20-30-uCOS30-40"><a href="#汇编20-中断20-定时器20-30-uCOS30-40" class="headerlink" title="汇编20%+中断20%+定时器20-30%+uCOS30-40%"></a>汇编20%+中断20%+定时器20-30%+uCOS30-40%</h3><h4 id="ucos"><a href="#ucos" class="headerlink" title="ucos"></a>ucos</h4><p>标准任务函数是什么样子，无返回，带一个指针</p>
<p>如何创建一个ucos任务，每一个参数都得清楚。</p>
<p>时钟单位为滴答，但这个滴答的时间片可能会不同</p>
<p>优先级相同的情况下如何实现分时调度。时间片长度会有不同</p>
<p>时间片的一些函数的参数和使用</p>
<p>信号量加锁的创建和使用。互斥和同步</p>
<p>事件组。发布事件，等待事件。。。    特别是其中的一些opt的含义</p>
<h3 id="复习"><a href="#复习" class="headerlink" title="复习"></a>复习</h3><h4 id="汇编"><a href="#汇编" class="headerlink" title="汇编"></a>汇编</h4><p>通用寄存器 r1-r12</p>
<p>专用寄存器：R13保存堆栈的栈顶地址   </p>
<p>R14链接寄存器，保存过程调用调用的返回地址  </p>
<p>R15程序计数器。 保存下一条要执行的指令的地址  </p>
<p>xPSR保存程序运行过程中的一些状态 N负数 Z零 C借位或进位 V溢出 Q饱和标志</p>
<p><strong>伪指令</strong>：</p>
<p>DCD 5        //DCD X : 分配4bytes空间并且把X的值，填入此处</p>
<p>SPACE 40   //SPACE X : 在此处开辟 X 个字节的空间，内容不定。</p>
<p>“段”：  分区域<br>                代码段 这个区域都是代码<br>                数据段 这个区域存放的是全局的数据<br>                堆栈段 stack</p>
<p>AREA 段名1, 段的属性1， 段的属性2， …<br>                eg：        AREA  mstack, DATA, READWRITE</p>
<p>段的属性1：<br>                    CODE  代码段<br>                    CODE32  thumb-2代码<br>                    DATA  数据段</p>
<p>属性2：ALIGN=3   8字节对齐(2的3次幂对齐)</p>
<p>宏指令：stack_size  EQU  0x200 ; // 定义一个宏</p>
<p>一个启动 .s文件（start.s），至少需要包含三个段:        </p>
<p>​                ; //堆栈段<br>​                ; //中断向量表<br>​                ; //代码段</p>
<p>ARM指令</p>
<p><opcode>{<cond>}{S} <Rd>, <operand1> {, <operand2>}</p>
<p>MOV ADD SUB LDR CMP比较相等    LSL逻辑左移 LSR逻辑右移</p>
<p>条件</p>
<p>MOVEQ R0, #250</p>
<ul>
<li>EQ                Equal(相等)             Z==1</li>
<li>NE                Not Equal(不相等)       Z==0</li>
<li>LT                Less Than    &lt;                N != V</li>
<li>GT                Greater Than    &gt;            (N == V) &amp;&amp; (Z == 0)</li>
</ul>
<p>S:  Status 表示该指令执行结果是否影响xPSR(程序状态寄存器)的标志位</p>
<p>LDR{cond} {S}    {B/H}    Rd, &lt;地址&gt;<br>STR{cond}       {B/H}    Rd, &lt;地址&gt;</p>
<p>LDR 加载，把存储器&lt;地址&gt;中的内容加载到 寄存器Rd中<br>STR 存储，把寄存器Rd中的内容，存储到存储器&lt;地址&gt;中去</p>
<figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">LDR R0, =0x20001000</span><br><span class="line"></span><br><span class="line">LDR R1, [R0, #0x12]</span><br><span class="line">[R0+0x12] -&gt; R1</span><br><span class="line"></span><br><span class="line">给存储器0x20001000单元写入一个整数（-2）</span><br><span class="line">MOV R0,#-2</span><br><span class="line">LDR R1,=0X20001000</span><br><span class="line">STR R0,[R1]</span><br></pre></td></tr></table></figure>

<p>地址确定方式： 基址寄存器 + 偏移量</p>
<pre><code>                    地址值    
[Rn]                Rn
--------------------------------------------------
[Rn, 偏移量]          Rn + 偏移量        Rn值不变
[Rn, 偏移量]!        Rn + 偏移量        Rn值+偏移量
[Rn], 偏移量        Rn                Rn值=Rn +  偏移量
</code></pre>
<p>多寄存器加载   LDM  Loader Multi<br>多寄存器存储   STM    Store  Multi</p>
<pre><code>LDM&#123;cond&#125;&lt;模式&gt;  Rn&#123;!&#125;, reglist
STM&#123;cond&#125;&lt;模式&gt;    Rn&#123;!&#125;, reglist
Rn指定了一个存储器的地址

!  可加可不加
加： 表示最后存储器的地址写入到Rn中去。
不加： 最后Rn的值不变
</code></pre>
<p>由&lt;模式&gt;来指定:<br>                注意：无论是哪种模式，低地址都是对应编号低的寄存器<br>                    IA: Incrememt After() 每次传送后地址自动增加(+4) &lt;—–<br>                    DB: Decrement Before  每次传送前地址自动减少(-4) &lt;—–<br>                    IB: Increment Before  每次传送前地址先自动增加(+4)<br>                    DA：Decrement After   每次传送后地址自动减少(-4)</p>
<p>任务：将R0-R3放到存储器单元0x20000200开始的递减连续单元存放，然后再恢复<br>                MOV R1,#1<br>                MOV R2,#2<br>                MOV R3,#3<br>                LDR R4,=0X20000200<br>                STMDA R4!,{R1-R3}<br>                LDMIB R4!,{R1-R3}</p>
<p><strong>伪指令</strong> LDR Rd, =expr    &lt;=&gt;    MOV Rd, #expr 如果是立即数的话</p>
<p>分支指令:用来实现代码的跳转<br>        有两种方式可以实现程序的跳转 类似函数的调用</p>
<pre><code>(1) 分支指令
B   lable ;  lable -&gt; PC,  不带返回的跳转 跳转类似于return
BL  lable ;     过程调用，函数调用 带返回的
            把下一条指令的地址 -&gt; LR
            lable -&gt; PC

(2) 直接向PC寄存器赋值
MOV PC, LR
MOV PC, #0x80000000
</code></pre>
<p><strong>循环</strong>是如何实现的</p>
<pre><code>for (i = 1, sum = 0; i &lt;= 10;i++)
&#123;
    sum = sum + i;
&#125;        
=&gt;
    初始条件 i--R0==1,sum--R1==0
    循环条件：R0&lt;=10  ---CMP R0,#10 LE 就执行循环 GT 跳出循环 (到结束的地方lable) B 
    循环体：用两个标号，分别标识循环体的开始和结束
            ;只用一个标号，也可以，标识循环体的开始
    loop_sum
        CMP R0,#10
        BGT loop_sum_end    当不满足的时候就跳转到结束的label
        ADD R1,R1,R0
        ADD R0,R0,#1
        B loop_sum    
    loop_sum_end
</code></pre>
<p>记住:<strong>过程调用</strong>就是这样</p>
<figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">label PROC</span><br><span class="line">    PUSH</span><br><span class="line">    （看你的）</span><br><span class="line">    POP</span><br><span class="line">    ENDP</span><br></pre></td></tr></table></figure>

<p>入口参数传送用 R0, R1,R2, R3,如果超过4个参数，后面的参数需要放到栈空间</p>
<p>函数的返回值用R0</p>
<p>“现场保护”  PUSH R0-R12 LR </p>
<p>“现场恢复”    POP    </p>
<figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">sum_two PROC</span><br><span class="line">    PUSH &#123;R2-R12,LR&#125;	;LR is for return</span><br><span class="line">    ADD R0,R0,R1</span><br><span class="line"></span><br><span class="line">    POP &#123;R2-R12,PC&#125;</span><br><span class="line">    ENDP</span><br></pre></td></tr></table></figure>



<p><strong>汇编文件 与 C文件共存</strong>    需要两个文件在同一个文件夹里面</p>
<pre><code>第一点：汇编中如何调用C代码
1.需要在汇编文件，&quot;进口&quot;：引入相应的全局变量名或全局函数， “符号”
        IMPORT  函数名or全局变量名 
2.直接调用就好
 BL sum_three

第二点：C文件中如何调用汇编
1.申明是外部函数 例如：extern int sum_two(int, int);
2.直接调用汇编过程（写对应的过程名就好）
3.回到汇编代码中还需要说明该函数是“出口”函数
需要用EXPORT把相应的全局变量名或全局函数名，导出
EXPORT sum_two
</code></pre>
<h4 id="中断"><a href="#中断" class="headerlink" title="中断"></a>中断</h4><p><strong>固件库编程常规步骤</strong> </p>
<p>AHB/APB1/APB2时钟使能</p>
<p>GPIO初始化，需要对里面的一些属性进行配置</p>
<figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">GPIO_InitTypeDef p;</span><br><span class="line">P.GPIO_Pin= GPIO_Pin_9|GPIO_Pin_10;</span><br><span class="line">P.GPIO_Mode = GPIO_Mode_OUT;</span><br><span class="line">P.GPIO_Speed = GPIO_Speed_50MHz;</span><br><span class="line">P.GPIO_OType = GPIO_OType_PP;</span><br><span class="line">P.GPIO_PuPd = GPIO_PuPd_NOPULL ;	</span><br><span class="line">GPIO_Init(GPIOF,&amp;P);</span><br></pre></td></tr></table></figure>

<p>初始化置位</p>
<p>中断：CPU指令执行过程中，被“紧急”事件打断，（中断响应）<br>        停止正在运行的程序并转入处理新情况的程序，（中断处理）<br>        处理完毕后又返回原被暂停的程序继续运行。（中断返回）</p>
<p>M4给不同的事件(中断),一个唯一的中断编号，当不同的中断事件产生时，MCU作不同的处理。通过中断向量表</p>
<p>中断向量表是什么呢？　 一个数组,保存不同的中断事件处理函数的地址的数组。</p>
<p>中断处理函数类型，一般为:<br>            void xxx_isr(void) 注意：这里的函数名要与中断向量表中一致，如果自己要进行重写的话。</p>
<p>说明：1.中断处理函数，无入口参数，无返回值。<br>              2.中断函数与普通函数的区别？<br>                普通函数：<br>                用户主动调用的，可以备好参数、可以有返回值<br>                中断函数：<br>                cpu被动调用，不是用户主动调用的。<br>                中断在任何时刻都可产生，产生就执行了。<br>                无参数，无返回值。</p>
<p>中断的产生需要两个阶段</p>
<p><strong>中断源的控制</strong></p>
<p><strong>中断控制器的控制NVIC</strong></p>
<p>然后对按键中断（外部中断）进行对应</p>
<p>外部中断是指GPIO的外部电路上产生的中断 (如按键中断)<br>        EXTI: external interrupt 外部中断<br>        STM32F4的中断控制器支持23个外部中断/事件请求<br>            EXTI0-EXTI22<br>        EXTI线0~15：对应外部IO口的输入中断<br>        GPIOx.0映射到EXTI0<br>        GPIOx.1映射到EXTI1<br>        GPIOx.15映射到EXTI15<br>注意：一条中断线的在同一时间只能被一个IO口映射。<br>例子：KEY0—PA0—EXTI0—-EXTI0_IRQHandler</p>
<p>外部中断的代码实现      KEY0 -&gt; PA0 -&gt; EXTI0 -&gt; NVIC -&gt; CPU EXTI0_IRQHandler </p>
<p>过程：</p>
<ul>
<li><p>GPIO控制器的配置</p>
<ul>
<li>RCC_AHB1 使能GPIO分组的时钟</li>
<li>GPIO_Init 配置</li>
</ul>
</li>
<li><p>SYSCFG选择器的配置</p>
<ul>
<li><p>使能SYSCFG外设的时钟</p>
<figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);</span><br></pre></td></tr></table></figure></li>
<li><p>选择相应的GPIO引脚作为外部中断的输入引脚</p>
<figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">例子：选择PA0 -&gt; EXTI0</span><br><span class="line">SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA,EXTI_PinSource0 );</span><br></pre></td></tr></table></figure></li>
</ul>
</li>
<li><p>EXTI外部中断控制器的配置</p>
<figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">EXTI_InitTypeDef e;</span><br><span class="line">e.EXTI_Line = EXTI_Line0 | EXTI_Line2 | EXTI_Line3 | EXTI_Line4;</span><br><span class="line">e.EXTI_LineCmd = ENABLE;</span><br><span class="line">e.EXTI_Mode = EXTI_Mode_Interrupt;</span><br><span class="line">//	e.EXTI_Trigger = EXTI_Trigger_Rising_Falling;	// 双边触发方式，就是按键在按下和松开都会有处理</span><br><span class="line">e.EXTI_Trigger = EXTI_Trigger_Falling; // 只在上边缘的时候会进行操作</span><br><span class="line"></span><br><span class="line">EXTI_Init(&amp;e);</span><br></pre></td></tr></table></figure></li>
<li><p>NVIC的控制</p>
<figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); // 抢占优先级的准备位数为两位</span><br><span class="line"></span><br><span class="line">NVIC_InitTypeDef ic;</span><br><span class="line"></span><br><span class="line">ic.NVIC_IRQChannel = EXTI0_IRQn;</span><br><span class="line">ic.NVIC_IRQChannelCmd = ENABLE;</span><br><span class="line">ic.NVIC_IRQChannelPreemptionPriority = 2; //抢占优先级为2，数字越低，优先级越高</span><br><span class="line">ic.NVIC_IRQChannelSubPriority = 2;		  //子优先级为2</span><br><span class="line"></span><br><span class="line">NVIC_Init(&amp;ic);</span><br></pre></td></tr></table></figure></li>
<li><p>然后重写中断函数</p>
<figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">// 需要在这里面判断一下是否触发了中断，之后还要进行清除</span><br><span class="line">void EXTI0_IRQHandler()</span><br><span class="line">&#123;</span><br><span class="line">	if (EXTI_GetFlagStatus(EXTI_Line0) == SET)</span><br><span class="line">	&#123;</span><br><span class="line"></span><br><span class="line">		// GPIO_ToggleBits(GPIOF, GPIO_Pin_9);</span><br><span class="line">		// uint32_t mstime = 200;</span><br><span class="line">		// Delay_ms(mstime); // 等待2000ms</span><br><span class="line">		status = 1;</span><br><span class="line">		// delay(0x5000); // 加一个delay，防止出现顺序的混乱</span><br><span class="line">		EXTI_ClearFlag(EXTI_Line0);</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li>
</ul>
<h4 id="定时器"><a href="#定时器" class="headerlink" title="定时器"></a>定时器</h4><p>时钟会有一个时钟周期T和频率（单位时间内（电平）完成周期性变化的次数）F        T*F = 1    </p>
<p>f = 1000 HZ   1s 1000次变化    =&gt; T = 1ms    周期    </p>
<p>时钟信号是通过晶振产生的      “晶振”：产生周期性的信号 这里默认为8M    然后通过分频/倍频变换成不同的频率</p>
<p>不同的总线有不同的最大允许频率</p>
<ul>
<li>AHB 域的最大频率为 168 MHz</li>
<li>低速 APB1 域的最大允许频率为 42 MHz</li>
<li>高速 APB2 域的最大允许频率为 84MHz</li>
</ul>
<p>定时器可分为3个部分</p>
<ul>
<li><p>时基单元。“计数器”可以设置为从设定值递减到0,也可以设置从0按照递增到设定值。然后产生一个溢出事件/中断，从而达到定时的功能</p>
<figure class="highlight c"><table><tr><td class="code"><pre><span class="line">例子:</span><br><span class="line">    假设一个定时器TIM的时钟频率为 f,</span><br><span class="line">    设定的计数值为N,按照递减的方式来计数				</span><br><span class="line">        每隔　(<span class="number">1</span>/f)s 就会 <span class="number">-1</span></span><br><span class="line">        N -&gt; <span class="number">0</span> =&gt; (N+<span class="number">1</span>) * (<span class="number">1</span>/f) s				</span><br><span class="line">    到<span class="number">0</span>,产生一个中断，时间为: (N+<span class="number">1</span>) * (<span class="number">1</span>/f) s</span><br><span class="line"></span><br><span class="line">    －－－－－－</span><br><span class="line">    假设：	f = <span class="number">8</span>M Hz，定时<span class="number">1</span>s,怎么设定N</span><br><span class="line">        N * (<span class="number">1</span>/<span class="number">8</span>M)s = <span class="number">1</span>s</span><br><span class="line">        N = <span class="number">8000000</span> - <span class="number">1</span> = <span class="number">799999</span>	</span><br></pre></td></tr></table></figure>

<p>内部有三个寄存器：</p>
<pre><code>        TIMx_ARR: Auto Reload Register 自动加载寄存器　&lt;- N
        TIMx_CNT: Counter 计数器
        TIMx_PSC: PreSCaler 时钟预分频    

        “溢出事件/中断”
            　单向递增 0 -&gt; N  =&gt; 产生溢出事件/中断
            　单向递减 N -&gt; 0  =&gt; 产生溢出事件/中断
</code></pre>
</li>
<li><p>输入捕获单元：对一个或多个输入信号进行处理</p>
</li>
<li><p>输出比较单元：输出一个或多个信号</p>
</li>
</ul>
<p>然后有一些系统内部定义的定时器 TIM13 TIM6 TIM7……</p>
<p>音乐的播放    music.c</p>
<ul>
<li><p>时钟使能    TIM13（APB1）和GPIO(AHB1)都要使能</p>
<figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE);</span><br><span class="line">RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM13, ENABLE); // 使能 apb1 tim13</span><br></pre></td></tr></table></figure></li>
<li><p>GPIO-PF8复用–AF–TIM13</p>
<figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">GPIO_InitTypeDef p;</span><br><span class="line">p.GPIO_Pin = GPIO_Pin_8;</span><br><span class="line">p.GPIO_Mode = GPIO_Mode_AF; //多路复用模式，注意这个新模式</span><br><span class="line">p.GPIO_PuPd = GPIO_PuPd_NOPULL;</span><br><span class="line">p.GPIO_Speed = GPIO_Speed_50MHz;</span><br><span class="line">GPIO_Init(GPIOF, &amp;p);</span><br><span class="line">GPIO_PinAFConfig(GPIOF, GPIO_PinSource8, GPIO_AF_TIM13);</span><br></pre></td></tr></table></figure></li>
<li><p><em>配置时基单元</em>    这里指定定时器的预分频</p>
<figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">TIM_TimeBaseInitTypeDef t;</span><br><span class="line">t.TIM_Prescaler = 8399; //预分频值   10000HZ=TIM13_CLK  将84M变为10000 这个8399是通过一个分频公式算出来</span><br><span class="line"></span><br><span class="line">t.TIM_CounterMode = TIM_CounterMode_Down; //递减模式</span><br><span class="line">t.TIM_Period = f;                         //N值，由10000变为对应音符的频率</span><br><span class="line">t.TIM_RepetitionCounter = 0;              //不需要重复计数</span><br><span class="line">TIM_TimeBaseInit(TIM13, &amp;t);</span><br></pre></td></tr></table></figure></li>
<li><p><em>输出通道的配置</em></p>
<figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">TIM_OCInitTypeDef t_oc;</span><br><span class="line">t_oc.TIM_OCMode = TIM_OCMode_PWM2;         // 因为递减模式，所以选择PWM2</span><br><span class="line">t_oc.TIM_OCPolarity = TIM_OCPolarity_High; // 高电平为有效电平</span><br><span class="line">// 试题：注意这个TIM_OutputState，还有另外一个带N的属性（只针对高级定时器）</span><br><span class="line">t_oc.TIM_OutputState = TIM_OutputState_Enable;</span><br><span class="line">t_oc.TIM_Pulse = f * 0.9; // 比较寄存器里面的值，这个里面的0.9是在不同的歌里面不同  占空比（高电平所占比）为10%</span><br><span class="line">// 注意是通道一的初始化，因为TIM13在通道1</span><br><span class="line">TIM_OC1Init(TIM13, &amp;t_oc);</span><br><span class="line">TIM_OC1PreloadConfig(TIM13, TIM_OCPreload_Enable);</span><br></pre></td></tr></table></figure></li>
<li><p><em>使能定时器</em></p>
<figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">TIM_ARRPreloadConfig(TIM13, ENABLE); //</span><br><span class="line">TIM_Cmd(TIM13, ENABLE);</span><br></pre></td></tr></table></figure></li>
</ul>
<h4 id="ucos-1"><a href="#ucos-1" class="headerlink" title="ucos"></a>ucos</h4><p>标准任务函数是什么样子，无返回，带一个指针</p>
<figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">void led_loop(void *p_arg)</span><br></pre></td></tr></table></figure>

<p>如何创建一个ucos任务，每一个参数都得清楚。</p>
<figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">void</span>  <span class="title">OSTaskCreate</span> <span class="params">(OS_TCB        *p_tcb,</span></span></span><br><span class="line"><span class="params"><span class="function">                 <span class="comment">// p_tcb指向任务控制块</span></span></span></span><br><span class="line"><span class="params"><span class="function">                 <span class="comment">// OS_TCB这个结构体用来标识一个“任务”，</span></span></span></span><br><span class="line"><span class="params"><span class="function">                 <span class="comment">//　用来保存新创建的任务的一些信息的，如：　任务id,...</span></span></span></span><br><span class="line"><span class="params"><span class="function"></span></span></span><br><span class="line"><span class="params"><span class="function">    CPU_CHAR      *p_name,</span></span></span><br><span class="line"><span class="params"><span class="function">            <span class="comment">//字符串，任务的名字。</span></span></span></span><br><span class="line"><span class="params"><span class="function"></span></span></span><br><span class="line"><span class="params"><span class="function">    OS_TASK_PTR    p_task, <span class="comment">//指定“任务函数”，不能为空。比如是led_loop					</span></span></span></span><br><span class="line"><span class="params"><span class="function">    <span class="keyword">void</span>          *p_arg,　<span class="comment">//&quot;任务函数&quot;的参数，可以直接为0</span></span></span></span><br><span class="line"><span class="params"><span class="function"></span></span></span><br><span class="line"><span class="params"><span class="function"></span></span></span><br><span class="line"><span class="params"><span class="function">    OS_PRIO        prio,　<span class="comment">//指定任务的优先级, [2, OS_PRIO_MAX - 2]</span></span></span></span><br><span class="line"><span class="params"><span class="function">                                值越小，优先级越高。</span></span></span><br><span class="line"><span class="params"><span class="function"></span></span></span><br><span class="line"><span class="params"><span class="function">                如下三个参数用来指定<span class="string">&quot;任务栈&quot;</span>。</span></span></span><br><span class="line"><span class="params"><span class="function">                栈：用来保存函数的局部变量的一块内存，“先进后出”思想</span></span></span><br><span class="line"><span class="params"><span class="function">                来管理的一段内存。“栈”。</span></span></span><br><span class="line"><span class="params"><span class="function">                每个任务都必须要有自己的栈。</span></span></span><br><span class="line"><span class="params"><span class="function">                事先定义一个全局的数组，用来作“任务的栈空间”</span></span></span><br><span class="line"><span class="params"><span class="function">    CPU_STK       *p_stk_base, <span class="comment">//p_stk_base指向一块&quot;任务栈&quot;空间</span></span></span></span><br><span class="line"><span class="params"><span class="function">                                <span class="comment">//一般在应用中，指向一个已经定义好的数组</span></span></span></span><br><span class="line"><span class="params"><span class="function">                                CPU_STK :存放到栈中元素的最小单位</span></span></span><br><span class="line"><span class="params"><span class="function"></span></span></span><br><span class="line"><span class="params"><span class="function">                                如:</span></span></span><br><span class="line"><span class="params"><span class="function">                                    CPU_STK <span class="built_in">stack</span>[<span class="number">100</span>];</span></span></span><br><span class="line"><span class="params"><span class="function">                                            <span class="comment">// 100个元素，总空间大小为: 400字节</span></span></span></span><br><span class="line"><span class="params"><span class="function"></span></span></span><br><span class="line"><span class="params"><span class="function">    CPU_STK_SIZE   stk_limit,<span class="comment">// 设置一个栈的下限值，栈中剩余多少元素时&quot;报警&quot;</span></span></span></span><br><span class="line"><span class="params"><span class="function">    CPU_STK_SIZE   stk_size, <span class="comment">//指定任务栈中最多允许多少个元素</span></span></span></span><br><span class="line"><span class="params"><span class="function"></span></span></span><br><span class="line"><span class="params"><span class="function"></span></span></span><br><span class="line"><span class="params"><span class="function"></span></span></span><br><span class="line"><span class="params"><span class="function">    OS_MSG_QTY     q_size, <span class="comment">// 任务内部消息队列的消息数</span></span></span></span><br><span class="line"><span class="params"><span class="function">                    ucos会为每个任务创建一个消息队列，用于 IPC(进程P之间I通信C)</span></span></span><br><span class="line"><span class="params"><span class="function">    OS_TICK        time_quanta,<span class="comment">//指定该任务的时间片的长度</span></span></span></span><br><span class="line"><span class="params"><span class="function">                            <span class="comment">//以时钟嘀哒为单位，</span></span></span></span><br><span class="line"><span class="params"><span class="function">                            <span class="comment">// 时钟嘀哒：时钟中断的间隔时间</span></span></span></span><br><span class="line"><span class="params"><span class="function">                            <span class="comment">//如: SysTick　频率为　1000 Hz</span></span></span></span><br><span class="line"><span class="params"><span class="function">                            <span class="comment">//  　每1ms产生一个SysTick的时钟中断，这个时钟</span></span></span></span><br><span class="line"><span class="params"><span class="function">                                    中断的间隔称为“时钟嘀哒”													</span></span></span><br><span class="line"><span class="params"><span class="function"></span></span></span><br><span class="line"><span class="params"><span class="function">    <span class="keyword">void</span>          *p_ext, <span class="comment">//指向用户补允的存储区</span></span></span></span><br><span class="line"><span class="params"><span class="function">                            如:在栈空间越界啦的时候用</span></span></span><br><span class="line"><span class="params"><span class="function"></span></span></span><br><span class="line"><span class="params"><span class="function">    OS_OPT         opt,  	<span class="comment">//包含任务的特定的选项，　位域</span></span></span></span><br><span class="line"><span class="params"><span class="function"></span></span></span><br><span class="line"><span class="params"><span class="function">                <span class="comment">//包含任务的特定的选项，位域，可以 |:</span></span></span></span><br><span class="line"><span class="params"><span class="function">                  OS_OPT_TASK_NONE            No option selected</span></span></span><br><span class="line"><span class="params"><span class="function">                  OS_OPT_TASK_STK_CHK         Stack checking to be allowed <span class="keyword">for</span> the task</span></span></span><br><span class="line"><span class="params"><span class="function">                  OS_OPT_TASK_STK_CLR         Clear the <span class="built_in">stack</span> when the task is created</span></span></span><br><span class="line"><span class="params"><span class="function">                  OS_OPT_TASK_SAVE_FP         If the CPU has floating-point registers, save them</span></span></span><br><span class="line"><span class="params"><span class="function">                                             during a context <span class="keyword">switch</span>.</span></span></span><br><span class="line"><span class="params"><span class="function">                   OS_OPT_TASK_NO_TLS          If the caller doesn<span class="string">&#x27;t want or need TLS (Thread Local </span></span></span></span><br><span class="line"><span class="string"><span class="params"><span class="function">                                             Storage) support for the task.  If you do not include this</span></span></span></span><br><span class="line"><span class="string"><span class="params"><span class="function">                                             option, TLS will be supported by default.</span></span></span></span><br><span class="line"><span class="string"><span class="params"><span class="function"></span></span></span></span><br><span class="line"><span class="string"><span class="params"><span class="function">    如: OS_OPT_TASK_STK_CLR：　在创建任务时，清0 stack</span></span></span></span><br><span class="line"><span class="string"><span class="params"><span class="function"></span></span></span></span><br><span class="line"><span class="string"><span class="params"><span class="function"></span></span></span></span><br><span class="line"><span class="string"><span class="params"><span class="function"></span></span></span></span><br><span class="line"><span class="string"><span class="params"><span class="function">    OS_ERR        *p_err  //用来保存出错信息的，</span></span></span></span><br><span class="line"><span class="string"><span class="params"><span class="function">                         // 在uCOS中用一个结构体OS_ERR来表示出错码的。</span></span></span></span><br><span class="line"><span class="string"><span class="params"><span class="function">                        OS_ERR_NONE ：没有错误。</span></span></span></span><br><span class="line"><span class="string"><span class="params"><span class="function">    );</span></span></span></span><br></pre></td></tr></table></figure>

<figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">------在用户创建第一个任务前，uCOS本身需要一些初始化:</span><br><span class="line">	void	OSInit(OS_ERR *p_err);</span><br><span class="line">				uCOS-III初始化函数，必须在调用其他任何uCOS-III的函数前先调用。</span><br><span class="line"></span><br><span class="line">------在创建完任务之后，就需要进行启动</span><br><span class="line">	void OSStart(OS_ERR *p_err);</span><br><span class="line">			启动ucos的多任务管理系统，该函数不会返回。</span><br></pre></td></tr></table></figure>

<p>ucos流程  （定义块 定义栈 任务函数 无返回带指令/main函数中有初始化 创建任务 执行任务）</p>
<p>时钟单位为滴答，但这个滴答的时间片可能会不同 </p>
<figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">OS_CFG_TICK_RATE_HZ -&gt; 1000</span><br><span class="line">表示1s SysTick定时器产生中断 1000次，每1ms产生一个SysTick</span><br></pre></td></tr></table></figure>



<p>优先级相同的情况下如何实现分时调度。时间片长度会有不同</p>
<figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">uCOS-III　提供“分时”特性</span><br><span class="line">当两个或以上的任务优先级相同，且是最高时，</span><br><span class="line">此时，你可以 enable  分时特性</span><br><span class="line">    “时间片轮转调度” -&gt; RoundRobin</span><br><span class="line"></span><br><span class="line">a. 可以调用函数OSSchedRoundRonbinCfg  -&gt; enable/disalbe这个“分时”</span><br><span class="line">        OSSchedRoundRobinCfg(CPU_BOOLEAN en,  //enable/disable</span><br><span class="line">            OS_TICK dflt_time_quanta,   //时间片长度</span><br><span class="line">            OS_ERR * p_err);</span><br><span class="line"></span><br><span class="line">b. os_cfg.h</span><br><span class="line">    #define OS_CFG_SCHED_ROUND_ROBIN_EN  1u</span><br><span class="line"></span><br><span class="line">c.开启时钟中断 </span><br><span class="line">BSP_Init();//初始化BSP</span><br><span class="line">BSP_TICK_Init();//初始化systick时钟</span><br><span class="line">特别注意：两个初始化的放置点一定要在串口初始化之前。</span><br></pre></td></tr></table></figure>

<p>时间片的一些函数的参数和使用</p>
<figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">有两种延时函数，一个是直接控制时间滴答的数量，一个是封装之后，只需要控制自己想要的时间</span><br><span class="line">1：</span><br><span class="line">void  OSTimeDly (OS_TICK   dly, </span><br><span class="line">    //要延时的时间节拍数。以Tick(时钟嘀哒)为单位。</span><br><span class="line">                    具体时间，需要结合第二个参数</span><br><span class="line"> OS_OPT    opt,	模式</span><br><span class="line">        &quot;相对模式&quot;: 相对当前的时钟嘀哒数</span><br><span class="line">            OS_OPT_TIME_DLY</span><br><span class="line">            OS_OPT_TIME_TIMEOUT</span><br><span class="line">                 延时的时间= OSTickCtr + dly</span><br><span class="line">        &quot;绝对模式&quot;: 以绝对时钟时刻为超时时间</span><br><span class="line">            OS_OPT_TIME_MATCH:  </span><br><span class="line">                延时的时间= dly</span><br><span class="line">        &quot;周期模式&quot;：</span><br><span class="line">            //OS_OPT_TIME_PERIODIC: OSTCBCurPtr.TickCtrPrev + dly</span><br><span class="line"></span><br><span class="line"> OS_ERR   *p_err  保存出错信息</span><br><span class="line">             OS_ERR_NONE            the call was successful and the delay occurred.</span><br><span class="line">             OS_ERR_OPT_INVALID     if you specified an invalid option for this function.</span><br><span class="line">            OS_ERR_SCHED_LOCKED    can&#x27;t delay when the scheduler is locked.</span><br><span class="line">             OS_ERR_TIME_DLY_ISR   当您在中断中调用此函数时，会报这个错</span><br><span class="line">                                    在中断中，不允许　“放弃cpu”.</span><br><span class="line">             OS_ERR_TIME_ZERO_DLY   if you specified a delay of zero.</span><br><span class="line"></span><br><span class="line"> );	</span><br><span class="line"> </span><br><span class="line">2：</span><br><span class="line">HMSM: H(hour) 小时</span><br><span class="line">      M(minute) 分钟</span><br><span class="line">      S(second)　秒</span><br><span class="line">      M(microsecond) 毫秒</span><br><span class="line"></span><br><span class="line">void  OSTimeDlyHMSM (CPU_INT16U   hours,</span><br><span class="line">         CPU_INT16U   minutes,</span><br><span class="line">         CPU_INT16U   seconds,</span><br><span class="line">         CPU_INT32U   milli,</span><br><span class="line">         OS_OPT       opt,</span><br><span class="line">         OS_ERR      *p_err);</span><br><span class="line"></span><br><span class="line">            H</span><br><span class="line">            M</span><br><span class="line">            S</span><br><span class="line">            M</span><br><span class="line">        opt:选项</span><br><span class="line">            OS_OPT_TIME_DLY  //	OS_OPT_TIME_TIMEOUT</span><br><span class="line">            OS_OPT_TIME_MATCH</span><br><span class="line">            以上两个选项，任选其一，表示是“相对时间”还是“绝对时间”</span><br><span class="line"></span><br><span class="line">            以下两个选项，任选其一</span><br><span class="line">            OS_OPT_TIME_HMSM_STRICT 　严格参数　</span><br><span class="line">                    0 &lt;= mitnutes &lt;= 59</span><br><span class="line">                    0 &lt;= seconds &lt;= 59</span><br><span class="line">                    0 &lt;= millo &lt;= 999</span><br><span class="line">            OS_OPT_TIME_HMSM_NON_STRICT　非严格参数</span><br><span class="line">            </span><br><span class="line">            </span><br><span class="line">OSTimeDlyHMSM让任务等待一个特定的事件（“超时事件”产生）</span><br><span class="line">这两个函数就是让任务让出CPU，从运行态到等待态。</span><br></pre></td></tr></table></figure>

<p>信号量加锁的创建和使用。互斥和同步    P V操作</p>
<figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">P  加锁	</span><br><span class="line">    ......</span><br><span class="line">    临界区:操作共享资源(被保护对象)的代码区域</span><br><span class="line">    .....</span><br><span class="line">V  解锁</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">创建一个互斥信号量</span><br><span class="line">void  OSMutexCreate (OS_MUTEX  *p_mutex,</span><br><span class="line">             CPU_CHAR  *p_name,</span><br><span class="line">             OS_ERR    *p_err);</span><br><span class="line">    p_mutex: 指向要初始化的信号量结构体</span><br><span class="line">        在uCOS-III,类型OS_MUTEX表示互斥信号量的类型</span><br><span class="line">    p_name: 信号量的名字</span><br><span class="line">    p_err: 用来保存出错信息。</span><br><span class="line"></span><br><span class="line">例子:</span><br><span class="line">    OS_MUTEX lock;</span><br><span class="line">    OSMutexCreate(&amp;lock, &quot;xxx&quot;, &amp;err);</span><br><span class="line">    </span><br><span class="line">信号量的P操作</span><br><span class="line">void  OSMutexPend (OS_MUTEX  *p_mutex,</span><br><span class="line">           OS_TICK    timeout,</span><br><span class="line">           OS_OPT     opt,</span><br><span class="line">           CPU_TS    *p_ts,</span><br><span class="line">           OS_ERR    *p_err);</span><br><span class="line"></span><br><span class="line">    p_mutex: 指向要等待(获取)的信号量</span><br><span class="line">    timeout: 指定等待超时时间(以时钟节拍为单位)</span><br><span class="line">    opt: 等待选项</span><br><span class="line">         OS_OPT_PEND_BLOCKING　　阻塞等待，获取不了的话，则阻塞</span><br><span class="line">         OS_OPT_PEND_NON_BLOCKING 非阻塞，</span><br><span class="line">                能获取则获取，不能获取，则走人。</span><br><span class="line">    p_ts: TS timesamp 时间戳。用来记录信号量释放的时间的。</span><br><span class="line">    p_err: 保存出错信息的。一定要解析</span><br><span class="line">          OS_ERR_NONE: 表示您已经获取这个信号量啦</span><br><span class="line">          OS_ERR_MUTEX_OWNER　：　你已经获取，又调用P报这个错</span><br><span class="line">            OS_ERR_OBJ_DEL </span><br><span class="line">            ……</span><br><span class="line"></span><br><span class="line">信号量的V操作</span><br><span class="line">void  OSMutexPost (OS_MUTEX  *p_mutex,</span><br><span class="line">                       OS_OPT     opt,</span><br><span class="line">                       OS_ERR    *p_err);</span><br><span class="line">    p_mutex: 指向要释放的信号量</span><br><span class="line">    opt: 释放选项</span><br><span class="line">        OS_OPT_POST_NONE  采用默认选项</span><br><span class="line">        OS_OPT_POST_NO_SCHED	不在本函数内部调度任务</span><br><span class="line">    p_err: 记录出错码，一定要判断出错码</span><br></pre></td></tr></table></figure>

<p>事件组。发布事件，等待事件。。。    特别是其中的一些opt的含义</p>
<figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">“生产者－消费者”　模型</span><br><span class="line">使用事件解决轮询的问题</span><br><span class="line"></span><br><span class="line">创建事件组 OSFlagCreate</span><br><span class="line"></span><br><span class="line">void  OSFlagCreate (OS_FLAG_GRP  *p_grp,</span><br><span class="line">                CPU_CHAR     *p_name,</span><br><span class="line">                OS_FLAGS      flags,</span><br><span class="line">                OS_ERR       *p_err);</span><br><span class="line"></span><br><span class="line">        p_grp: 指向要初始化的事件标记组。</span><br><span class="line">             OS_FLAG_GRP 用来表示一个事件标记组(os.h中定义)</span><br><span class="line">        p_name: 事件标记组的名字</span><br><span class="line">        flags: 事件初始值。</span><br><span class="line">                uCOS-III事件标记，是用bit位来实现的。</span><br><span class="line">                uint32 一个事件标记组，最多有32个事件。</span><br><span class="line">                     你可以在一个事件标记组中定义最多32个事件。</span><br><span class="line">                     每个事件占一个bit位。事件的具体含义由</span><br><span class="line">                     程序员来定义。相应的bit为１，表示该事件产生</span><br><span class="line">                     啦，为0表示还没有产生</span><br><span class="line"></span><br><span class="line">                    如:你定义事件确定对应的bit</span><br><span class="line">                        #define EV_FLAG_YOU_DATA   (1 &lt;&lt;8)   //有“数据”啦的事件，	</span><br><span class="line">                                                            //用第8bit来表示它。</span><br><span class="line">                        #define EV_FLAG_SPACE		(1 &lt;&lt;20) // ...</span><br><span class="line"></span><br><span class="line">        p_err: 用来保存出错信息的。</span><br><span class="line">        </span><br><span class="line">        </span><br><span class="line">等待事件</span><br><span class="line">		OSFlagPend</span><br><span class="line">		OS_FLAGS  OSFlagPend (OS_FLAG_GRP  *p_grp,</span><br><span class="line">                      OS_FLAGS      flags,</span><br><span class="line">                      OS_TICK       timeout,</span><br><span class="line">                      OS_OPT        opt,</span><br><span class="line">                      CPU_TS       *p_ts,</span><br><span class="line">                      OS_ERR       *p_err);</span><br><span class="line">				p_grp: 指向要等待的事件标记组</span><br><span class="line">				flags: 等待的事件标记位。表示要等待的哪些事件对应在哪些bit位上</span><br><span class="line">						如：　</span><br><span class="line">							事件EX (bit9)</span><br><span class="line">							事件EY(bit20)							</span><br><span class="line">							要事件EX 和事件EY的状态（如：等待EX产生，EY没产生）</span><br><span class="line">							(1 &lt;&lt; 9) | (1 &lt;&lt; 20)</span><br><span class="line">						只是指定您要等待的事件，在哪些bit位上，并不是表明</span><br><span class="line">						事件的状态。</span><br><span class="line">						更一般的做法是:把事件定义成宏。</span><br><span class="line">							#define EV_FLAG_XGT500   (1 &lt;&lt;9)   //有“数据”的事件，	</span><br><span class="line">														//用第8bit来表示它.	</span><br><span class="line">							#define EV_FLAG_Y	(1 &lt;&lt;20) // ...	</span><br><span class="line">						EV_FLAG_X | EV_FLAG_Y</span><br><span class="line">				timeout: 限时等待。　以tick为单位。				</span><br><span class="line">				opt:选项。表示要等待的事件的状态(1/0)</span><br><span class="line">						OS_OPT_PEND_FLAG_CLR_ALL: 等待所有指定的事件标记都清零（为0）</span><br><span class="line">					    OS_OPT_PEND_FLAG_CLR_ANY: 等待所有指定的事件标记有任意一个为0</span><br><span class="line">						OS_OPT_PEND_FLAG_SET_ALL: 等待所有指定的事件标记都置1（为1）</span><br><span class="line">						OS_OPT_PEND_FLAG_SET_ANY: 等待所有指定的事件标记有任意一个为1</span><br><span class="line">						以上四个选项任选其一，并与下面的两个选项“或”</span><br><span class="line">							OS_OPT_PEND_NON_BLOCKING  非阻塞等待</span><br><span class="line">							OS_OPT_PEND_BLOCKING		阻塞等待</span><br><span class="line">					例如：OS_OPT_PEND_FLAG_SET_ALL|OS_OPT_PEND_BLOCKING</span><br><span class="line">					等待所有指定的事件发生（标记都为1）否则就阻塞。</span><br><span class="line">					OS_OPT_PEND_FLAG_CONSUME:用来设置标志位是否在使用之后继续保持，</span><br><span class="line">					希望清零时使用。</span><br><span class="line">	</span><br><span class="line">				p_ts: TS timesamp 时间戳。用来记录事件发生的时间，若为NULL不会收到时间戳</span><br><span class="line">				p_err: 用来保存出错信息。</span><br><span class="line">			返回值:</span><br><span class="line">				 Returns    : The flags in the event flag group that made the task </span><br><span class="line">				 ready or, 0 if a timeout or an erroroccurred.</span><br><span class="line">				</span><br><span class="line">				返回0 表示事件没产生或出错啦。</span><br><span class="line">				&gt;0 哪些事件标记产生啦，如:  返回 0x5 bit0 bit2 所指示的事件产生（1是产生）。</span><br><span class="line">				</span><br><span class="line">				</span><br><span class="line">发布事件</span><br><span class="line">     OSFlagPost</span><br><span class="line">        OS_FLAGS  OSFlagPost (OS_FLAG_GRP  *p_grp,</span><br><span class="line">                  OS_FLAGS      flags,</span><br><span class="line">                  OS_OPT        opt,</span><br><span class="line">                  OS_ERR       *p_err);</span><br><span class="line">            p_grp: 事件标记组;</span><br><span class="line">            flags: 指定事件标记位，指定bit位(哪些事件)</span><br><span class="line">            opt: 指定要发布的事件是 Set还是Clear</span><br><span class="line">                    OS_OPT_POST_FLAG_SET  :指定的事件标记为1</span><br><span class="line">                    OS_OPT_POST_FLAG_CLR  :指定的事件标记为0</span><br><span class="line"></span><br><span class="line">            p_err: 用来保存出错信息</span><br><span class="line"></span><br><span class="line">        返回值:</span><br><span class="line">        the new value of the event flags bits that are still set.	</span><br><span class="line">            返回事件标记组的状态。</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">        例子:</span><br><span class="line">            OSFlagPost(p_pgr, 0x31, OS_OPT_POST_FLAG_SET, &amp;err);</span><br><span class="line">                    0011 0001							</span><br><span class="line">                        bit0 bit4 bit5 变为1</span><br><span class="line"></span><br><span class="line">            OSFlagPost(p_pgr, 0x31, OS_OPT_POST_FLAG_CLR, &amp;err);</span><br><span class="line">                    0011 0001							</span><br><span class="line">                        bit0 bit4 bit5 变为0</span><br></pre></td></tr></table></figure>

</div></article><div class="post-copyright"><div class="post-copyright__author"><span class="post-copyright-meta">文章作者: </span><span class="post-copyright-info"><a href="mailto:undefined">晟松</a></span></div><div class="post-copyright__type"><span class="post-copyright-meta">文章链接: </span><span class="post-copyright-info"><a href="https://chengsong.info/2021/06/05/嵌入式复习/">https://chengsong.info/2021/06/05/嵌入式复习/</a></span></div><div class="post-copyright__notice"><span class="post-copyright-meta">版权声明: </span><span class="post-copyright-info">本博客所有文章除特别声明外，均采用 <a target="_blank" rel="noopener" href="https://creativecommons.org/licenses/by-nc-sa/4.0/">CC BY-NC-SA 4.0</a> 许可协议。转载请注明来自 <a href="https://chengsong.info">晟松</a>！</span></div></div><div class="post-meta__tag-list"><a class="post-meta__tags" href="/tags/%E5%B5%8C%E5%85%A5%E5%BC%8F-%E5%A4%8D%E4%B9%A0/">嵌入式 复习</a></div><nav id="pagination"><div class="prev-post pull-left"><a href="/2021/11/19/springboot%E7%AE%80%E5%8D%95%E5%AD%A6%E4%B9%A0/"><i class="fa fa-chevron-left">  </i><span>springboot入门</span></a></div><div class="next-post pull-right"><a href="/2021/05/27/webpack%E5%AD%A6%E4%B9%A0/"><span>webpack学习</span><i class="fa fa-chevron-right"></i></a></div></nav></div></div><footer class="footer-bg" style="background-image: url(/img/blog-bg.jpg)"><div class="layout" id="footer"><div class="copyright">&copy;2020 - 2023 By 晟松</div><div class="framework-info"><span>驱动 - </span><a target="_blank" rel="noopener" href="http://hexo.io"><span>Hexo</span></a><span class="footer-separator">|</span><span>主题 - </span><a target="_blank" rel="noopener" href="https://github.com/Molunerfinn/hexo-theme-melody"><span>Melody</span></a></div><div class="icp"><a target="_blank" rel="noopener" href="http://www.beian.miit.gov.cn/"><span>湘ICP备2020021729号</span></a></div><div class="busuanzi"><script async src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script><span id="busuanzi_container_page_pv"><i class="fa fa-file"></i><span id="busuanzi_value_page_pv"></span><span></span></span></div></div></footer><i class="fa fa-arrow-up" id="go-up" aria-hidden="true"></i><script src="https://cdn.jsdelivr.net/npm/animejs@latest/anime.min.js"></script><script src="https://cdn.jsdelivr.net/npm/jquery@latest/dist/jquery.min.js"></script><script src="https://cdn.jsdelivr.net/npm/@fancyapps/fancybox@latest/dist/jquery.fancybox.min.js"></script><script src="https://cdn.jsdelivr.net/npm/velocity-animate@latest/velocity.min.js"></script><script src="https://cdn.jsdelivr.net/npm/velocity-ui-pack@latest/velocity.ui.min.js"></script><script src="/js/utils.js?version=1.9.0"></script><script src="/js/fancybox.js?version=1.9.0"></script><script src="/js/sidebar.js?version=1.9.0"></script><script src="/js/copy.js?version=1.9.0"></script><script src="/js/fireworks.js?version=1.9.0"></script><script src="/js/transition.js?version=1.9.0"></script><script src="/js/scroll.js?version=1.9.0"></script><script src="/js/head.js?version=1.9.0"></script><script src="/js/search/local-search.js"></script><script>if(/Android|webOS|iPhone|iPod|iPad|BlackBerry/i.test(navigator.userAgent)) {
  $('#nav').addClass('is-mobile')
  $('footer').addClass('is-mobile')
  $('#top-container').addClass('is-mobile')
}</script><div class="search-dialog" id="local-search"><div class="search-dialog__title" id="local-search-title">本地搜索</div><div id="local-input-panel"><div id="local-search-input"><div class="local-search-box"><input class="local-search-box--input" placeholder="搜索文章"></div></div></div><hr><div id="local-search-results"><div id="local-hits"></div><div id="local-stats"><div class="local-search-stats__hr" id="hr"><span>由</span> <a target="_blank" rel="noopener" href="https://github.com/wzpan/hexo-generator-search" style="color:#49B1F5;">hexo-generator-search</a>
 <span>提供支持</span></div></div></div><span class="search-close-button"><i class="fa fa-times"></i></span></div><div class="search-mask"></div></body></html>